home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 4 / The 640 Meg Shareware Studio CD-ROM Volume IV (Data Express)(1994).ISO / clang / rzsz0593.zip / RZ.C < prev    next >
C/C++ Source or Header  |  1993-05-05  |  28KB  |  1,291 lines

  1. #define VERSION "3.24 5-5-93"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*
  5.  *
  6.  * rz.c By Chuck Forsberg
  7.  *    Copyright 1993 Omen Technology Inc All Rights Reserved
  8.  *
  9.  * A program for Unix to receive files and commands from computers running
  10.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  11.  *  rz uses Unix buffered input to reduce wasted CPU time.
  12.  *
  13.  *
  14.  *    This version implements numerous enhancements including ZMODEM
  15.  *    Run Length Encoding and variable length headers.  These
  16.  *    features were not funded by the original Telenet development
  17.  *    contract.
  18.  * 
  19.  *  This software may be freely used for educational (didactic
  20.  *  only) purposes.  This software may also be freely used to
  21.  *  support file transfer operations to or from licensed Omen
  22.  *  Technology products.  Use with other commercial or shareware
  23.  *  programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION.
  24.  *
  25.  *  Any programs which use part or all of this software must be
  26.  *  provided in source form with this notice intact except by
  27.  *  written permission from Omen Technology Incorporated.
  28.  *
  29.  * 
  30.  * Use of this software for commercial or administrative purposes
  31.  * except when exclusively limited to interfacing Omen Technology
  32.  * products requires a per port license payment of $20.00 US per
  33.  * port (less in quantity, see mailer.rz).  Use of this code by
  34.  * inclusion, decompilation, reverse engineering or any other means
  35.  * constitutes agreement to these conditions and acceptance of
  36.  * liability to license the materials and payment of reasonable
  37.  * legal costs necessary to enforce this license agreement.
  38.  *
  39.  *
  40.  *        Omen Technology Inc
  41.  *        Post Office Box 4681
  42.  *        Portland OR 97208
  43.  *
  44.  *    This code is made available in the hope it will be useful,
  45.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  46.  *    DAMAGES OF ANY KIND.
  47.  *
  48.  *
  49.  *
  50.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  51.  *
  52.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  53.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  54.  *
  55.  *  -DMD may be added to compiler command line to compile in
  56.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  57.  *
  58.  *  HOWMANY may be tuned for best performance
  59.  *
  60.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  61.  */
  62.  
  63. char *Copyrrz = "Copyright 1993 Omen Technology Inc All Rights Reserved";
  64.  
  65.  
  66. #define LOGFILE "/tmp/rzlog"
  67. #define LOGFILE2 "rzlog"
  68. #include <stdio.h>
  69. #include <signal.h>
  70. #include <ctype.h>
  71. #include <errno.h>
  72. extern int errno;
  73.  
  74. #define OK 0
  75. #define FALSE 0
  76. #define TRUE 1
  77. #define ERROR (-1)
  78.  
  79. /*
  80.  * Max value for HOWMANY is 255.
  81.  *   A larger value reduces system overhead but may evoke kernel bugs.
  82.  */
  83. #ifndef HOWMANY
  84. #define HOWMANY 96
  85. #endif
  86.  
  87. /* Ward Christensen / CP/M parameters - Don't change these! */
  88. #define ENQ 005
  89. #define CAN ('X'&037)
  90. #define XOFF ('s'&037)
  91. #define XON ('q'&037)
  92. #define SOH 1
  93. #define STX 2
  94. #define EOT 4
  95. #define ACK 6
  96. #define NAK 025
  97. #define CPMEOF 032
  98. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  99. #define TIMEOUT (-2)
  100. #define RCDO (-3)
  101. #define GCOUNT (-4)
  102. #define ERRORMAX 5
  103. #define RETRYMAX 5
  104. #define WCEOT (-10)
  105. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  106. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  107.  
  108. int Zmodem=0;        /* ZMODEM protocol requested */
  109. int Nozmodem = 0;    /* If invoked as "rb" */
  110. unsigned Baudrate = 9600;
  111. unsigned Effbaud = 9600;
  112.  
  113.  
  114. #include "rbsb.c"    /* most of the system dependent stuff here */
  115. #include "crctab.c"
  116. char endmsg[90] = {0};    /* Possible message to display on exit */
  117.  
  118. char *substr();
  119. FILE *fout;
  120.  
  121. /*
  122.  * Routine to calculate the free bytes on the current file system
  123.  *  ~0 means many free bytes (unknown)
  124.  */
  125. unsigned long getfree()
  126. {
  127.     return(~0L);    /* many free bytes ... */
  128. }
  129.  
  130. int Lastrx;
  131. unsigned long rxbytes;
  132. int Crcflg;
  133. int Firstsec;
  134. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  135. int errors;
  136. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  137.  
  138. #define DEFBYTL 2000000000L    /* default rx file size */
  139. unsigned long Bytesleft;    /* number of bytes of incoming file left */
  140. long Modtime;        /* Unix style mod time for incoming file */
  141. int Filemode;        /* Unix style mode for incoming file */
  142. unsigned long Totalleft;
  143. unsigned long Filesleft;
  144. char Pathname[PATHLEN];
  145. char *Progname;        /* the name by which we were called */
  146.  
  147. int Batch=0;
  148. int Thisbinary;        /* current file is to be received in bin mode */
  149. int Rxbinary=FALSE;    /* receive all files in bin mode */
  150. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  151. int Blklen;        /* record length of received packets */
  152.  
  153. #ifdef SEGMENTS
  154. int chinseg = 0;    /* Number of characters received in this data seg */
  155. char secbuf[1+(SEGMENTS+1)*1024];
  156. #else
  157. char secbuf[1025];
  158. #endif
  159.  
  160.  
  161. time_t timep[2];
  162. char Lzmanag;        /* Local file management request */
  163. char Lzconv;        /* Local ZMODEM file conversion request */
  164. char zconv;        /* ZMODEM file conversion request */
  165. char zmanag;        /* ZMODEM file management request */
  166. char ztrans;        /* ZMODEM file transport request */
  167. int Zctlesc;        /* Encode control characters */
  168. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  169.  
  170. /*
  171.  * Log an error
  172.  */
  173. /*VARARGS1*/
  174. void
  175. zperr(s,p,u)
  176. char *s, *p, *u;
  177. {
  178.     if (Verbose <= 0)
  179.         return;
  180.     fprintf(stderr, "Retry %d: ", errors);
  181.     fprintf(stderr, s, p, u);
  182.     fprintf(stderr, "\n");
  183. }
  184.  
  185. #include "zm.c"
  186. #include "zmr.c"
  187.  
  188. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  189.  
  190. /* called by signal interrupt or terminate to clean things up */
  191. void
  192. bibi(n)
  193. {
  194.     if (Zmodem)
  195.         zmputs(Attn);
  196.     canit(); mode(0);
  197.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  198.     exit(3);
  199. }
  200.  
  201. main(argc, argv)
  202. char *argv[];
  203. {
  204.     register char *cp;
  205.     register npats;
  206.     char *virgin, **patts;
  207.     char *getenv();
  208.     int exitcode = 0;
  209.  
  210.     Rxtimeout = 100;
  211.     setbuf(stderr, NULL);
  212.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  213.         Restricted=TRUE;
  214.  
  215.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  216.     inittty();
  217.     npats = 0;
  218.     while (--argc) {
  219.         cp = *++argv;
  220.         if (*cp == '-') {
  221.             while( *++cp) {
  222.                 switch(*cp) {
  223.                 case '\\':
  224.                      cp[1] = toupper(cp[1]);  continue;
  225.                 case 'a':
  226.                     if (!Batch || Nozmodem)
  227.                         Rxascii=TRUE;
  228.                     else
  229.                         usage();
  230.                     break;
  231.                 case 't':
  232.                     if (--argc < 1) {
  233.                         usage();
  234.                     }
  235.                     Rxtimeout = atoi(*++argv);
  236.                     if (Rxtimeout<10 || Rxtimeout>1000)
  237.                         usage();
  238.                     break;
  239.                 case 'w':
  240.                     if (--argc < 1) {
  241.                         usage();
  242.                     }
  243.                     Zrwindow = atoi(*++argv);
  244.                     break;
  245.                 case 'v':
  246.                     ++Verbose; break;
  247.                 default:
  248.                     usage();
  249.                 }
  250.             }
  251.         }
  252.         else if ( !npats && argc>0) {
  253.             if (argv[0][0]) {
  254.                 npats=argc;
  255.                 patts=argv;
  256.             }
  257.         }
  258.     }
  259.     if (npats > 1)
  260.         usage();
  261.     if (Batch && npats)
  262.         usage();
  263.     if (Verbose) {
  264.         if (freopen(LOGFILE, "a", stderr)==NULL)
  265.             if (freopen(LOGFILE2, "a", stderr)==NULL) {
  266.                 printf("Can't open log file!");
  267.                 exit(2);
  268.             }
  269.         setbuf(stderr, NULL);
  270.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  271.     }
  272.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  273.     mode(1);
  274.     if (signal(SIGINT, bibi) == SIG_IGN) {
  275.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  276.     }
  277.     else {
  278.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  279.     }
  280.     signal(SIGTERM, bibi);
  281.     if (wcreceive(npats, patts)==ERROR) {
  282.         exitcode=1;
  283.         canit();
  284.     }
  285.     mode(0);
  286.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  287.         canit();
  288.     if (endmsg[0])
  289.         printf("  %s: %s\r\n", Progname, endmsg);
  290.     printf("%s %s finished.\r\n", Progname, VERSION);
  291.     fflush(stdout);
  292.     if(exitcode)
  293.         exit(1);
  294. #ifndef REGISTERED
  295.     /* Removing or disabling this code without registering is theft */
  296.     if (!Usevhdrs)  {
  297.         printf( "\n\n\nPlease read the License Agreement in rz.doc\n");
  298.         fflush(stdout);
  299.         sleep(10);
  300.     }
  301. #endif
  302.     exit(0);
  303. }
  304.  
  305.  
  306. usage()
  307. {
  308.     fprintf(stderr,
  309.     "Receive Files and Commands with ZMODEM/YMODEM/XMODEM Protocol\n\n");
  310.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  311.       Progname, VERSION, OS);
  312.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n\n");
  313.     fprintf(stderr,"Usage:    rz [-v]        (ZMODEM)\n");
  314.     fprintf(stderr,"or    rb [-av]    (YMODEM)\n");
  315.     fprintf(stderr,"or    rc [-av] file    (XMODEM-CRC)\n");
  316.     fprintf(stderr,"or    rx [-av] file    (XMODEM)\n\n");
  317.     fprintf(stderr,
  318. "Supports incoming ZMODEM binary (-b), ASCII CR/LF>NL (-a), newer(-n),\n\
  319.     newer+longer(-N), protect (-p), Crash Recovery (-r),\n\
  320. clobber (-y), match+clobber (-Y), compression (-Z), and append (-+).\n\n");
  321.     fprintf(stderr,"Copyright 1993 Omen Technology INC All Rights Reserved\n");
  322.     fprintf(stderr,
  323.     "See rz.doc for option descriptions and licensing information.\n\n");
  324.     exit(2);
  325. }
  326.  
  327. /*
  328.  * Let's receive something already.
  329.  */
  330.  
  331. char *rbmsg = "%s ready. Type \"%s file ...\" to your modem program\n\r";
  332.  
  333. wcreceive(argc, argp)
  334. char **argp;
  335. {
  336.     register c;
  337.  
  338.     if (Batch || argc==0) {
  339.         Crcflg=1;
  340.         fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  341.         if (c=tryz()) {
  342.             if (c == ZCOMPL)
  343.                 return OK;
  344.             if (c == ERROR)
  345.                 goto fubar;
  346.             c = rzfiles();
  347.             if (c)
  348.                 goto fubar;
  349.         } else {
  350.             for (;;) {
  351.                 if (wcrxpn(secbuf)== ERROR)
  352.                     goto fubar;
  353.                 if (secbuf[0]==0)
  354.                     return OK;
  355.                 if (procheader(secbuf) == ERROR)
  356.                     goto fubar;
  357.                 if (wcrx()==ERROR)
  358.                     goto fubar;
  359.             }
  360.         }
  361.     } else {
  362.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  363.  
  364.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  365.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  366.         if ((fout=fopen(Pathname, "w")) == NULL)
  367.             return ERROR;
  368.         if (wcrx()==ERROR)
  369.             goto fubar;
  370.     }
  371.     return OK;
  372. fubar:
  373.     canit();
  374.     Modtime = 1;
  375.     if (fout)
  376.         fclose(fout);
  377.     if (Restricted) {
  378.         unlink(Pathname);
  379.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  380.     }
  381.     return ERROR;
  382. }
  383.  
  384.  
  385. /*
  386.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  387.  * Length is indeterminate as long as less than Blklen
  388.  * A null string represents no more files (YMODEM)
  389.  */
  390. wcrxpn(rpn)
  391. char *rpn;    /* receive a pathname */
  392. {
  393.     register c;
  394.  
  395.     purgeline();
  396.  
  397. et_tu:
  398.     Firstsec=TRUE;  Eofseen=FALSE;
  399.     sendline(Crcflg?WANTCRC:NAK);  flushmo();
  400.     Lleft=0;    /* Do read next time ... */
  401.     while ((c = wcgetsec(rpn, 100)) != 0) {
  402.         if (c == WCEOT) {
  403.             zperr( "Pathname fetch returned %d", c);
  404.             sendline(ACK);  flushmo();
  405.             Lleft=0;    /* Do read next time ... */
  406.             readline(1);
  407.             goto et_tu;
  408.         }
  409.         return ERROR;
  410.     }
  411.     sendline(ACK);  flushmo();
  412.     return OK;
  413. }
  414.  
  415. /*
  416.  * Adapted from CMODEM13.C, written by
  417.  * Jack M. Wierda and Roderick W. Hart
  418.  */
  419.  
  420. wcrx()
  421. {
  422.     register int sectnum, sectcurr;
  423.     register char sendchar;
  424.     register char *p;
  425.     int cblklen;            /* bytes to dump this block */
  426.  
  427.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  428.     sendchar=Crcflg?WANTCRC:NAK;
  429.  
  430.     for (;;) {
  431.         sendline(sendchar);    /* send it now, we're ready! */
  432.         flushmo();
  433.         Lleft=0;    /* Do read next time ... */
  434.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  435.         if (sectcurr==(sectnum+1 &0377)) {
  436.             sectnum++;
  437.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  438.             if (putsec(secbuf, cblklen)==ERROR)
  439.                 return ERROR;
  440.             if ((Bytesleft-=cblklen) < 0)
  441.                 Bytesleft = 0;
  442.             sendchar=ACK;
  443.         }
  444.         else if (sectcurr==(sectnum&0377)) {
  445.             zperr( "Received dup Sector");
  446.             sendchar=ACK;
  447.         }
  448.         else if (sectcurr==WCEOT) {
  449.             if (closeit())
  450.                 return ERROR;
  451.             sendline(ACK); flushmo();
  452.             Lleft=0;    /* Do read next time ... */
  453.             return OK;
  454.         }
  455.         else if (sectcurr==ERROR)
  456.             return ERROR;
  457.         else {
  458.             zperr( "Sync Error");
  459.             return ERROR;
  460.         }
  461.     }
  462. }
  463.  
  464. /*
  465.  * Wcgetsec fetches a Ward Christensen type sector.
  466.  * Returns sector number encountered or ERROR if valid sector not received,
  467.  * or CAN CAN received
  468.  * or WCEOT if eot sector
  469.  * time is timeout for first char, set to 4 seconds thereafter
  470.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  471.  *    (Caller must do that when he is good and ready to get next sector)
  472.  */
  473.  
  474. wcgetsec(rxbuf, maxtime)
  475. char *rxbuf;
  476. int maxtime;
  477. {
  478.     register checksum, wcj, firstch;
  479.     register unsigned short oldcrc;
  480.     register char *p;
  481.     int sectcurr;
  482.  
  483.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  484.  
  485.         if ((firstch=readline(maxtime))==STX) {
  486.             Blklen=1024; goto get2;
  487.         }
  488.         if (firstch==SOH) {
  489.             Blklen=128;
  490. get2:
  491.             sectcurr=readline(1);
  492.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  493.                 oldcrc=checksum=0;
  494.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  495.                     if ((firstch=readline(1)) < 0)
  496.                         goto bilge;
  497.                     oldcrc=updcrc(firstch, oldcrc);
  498.                     checksum += (*p++ = firstch);
  499.                 }
  500.                 if ((firstch=readline(1)) < 0)
  501.                     goto bilge;
  502.                 if (Crcflg) {
  503.                     oldcrc=updcrc(firstch, oldcrc);
  504.                     if ((firstch=readline(1)) < 0)
  505.                         goto bilge;
  506.                     oldcrc=updcrc(firstch, oldcrc);
  507.                     if (oldcrc & 0xFFFF)
  508.                         zperr( "CRC");
  509.                     else {
  510.                         Firstsec=FALSE;
  511.                         return sectcurr;
  512.                     }
  513.                 }
  514.                 else if (((checksum-firstch)&0377)==0) {
  515.                     Firstsec=FALSE;
  516.                     return sectcurr;
  517.                 }
  518.                 else
  519.                     zperr( "Checksum");
  520.             }
  521.             else
  522.                 zperr("Sector number garbled");
  523.         }
  524.         /* make sure eot really is eot and not just mixmash */
  525.         else if (firstch==EOT && Lleft==0)
  526.             return WCEOT;
  527.         else if (firstch==CAN) {
  528.             if (Lastrx==CAN) {
  529.                 zperr( "Sender CANcelled");
  530.                 return ERROR;
  531.             } else {
  532.                 Lastrx=CAN;
  533.                 continue;
  534.             }
  535.         }
  536.         else if (firstch==TIMEOUT) {
  537.             if (Firstsec)
  538.                 goto humbug;
  539. bilge:
  540.             zperr( "TIMEOUT");
  541.         }
  542.         else
  543.             zperr( "Got 0%o sector header", firstch);
  544.  
  545. humbug:
  546.         Lastrx=0;
  547.         while(readline(1)!=TIMEOUT)
  548.             ;
  549.         if (Firstsec) {
  550.             sendline(Crcflg?WANTCRC:NAK);  flushmo();
  551.             Lleft=0;    /* Do read next time ... */
  552.         } else {
  553.             maxtime=40; sendline(NAK);  flushmo();
  554.             Lleft=0;    /* Do read next time ... */
  555.         }
  556.     }
  557.     /* try to stop the bubble machine. */
  558.     canit();
  559.     return ERROR;
  560. }
  561.  
  562.  
  563. /*
  564.  * Process incoming file information header
  565.  */
  566. procheader(name)
  567. char *name;
  568. {
  569.     register char *openmode, *p, **pp;
  570.     static dummy;
  571.     struct stat f;
  572.  
  573.     /* set default parameters and overrides */
  574.     openmode = "w";
  575.     Thisbinary = (!Rxascii) || Rxbinary;
  576.     if (zconv == ZCBIN && Lzconv != ZCRESUM)
  577.         Lzconv = zconv;            /* Remote Binary override */
  578.     if (Lzconv)
  579.         zconv = Lzconv;
  580.     if (Lzmanag)
  581.         zmanag = Lzmanag;
  582.  
  583.     /*
  584.      *  Process ZMODEM remote file management requests
  585.      */
  586.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  587.         Thisbinary = 0;
  588.     if (zconv == ZCBIN)    /* Remote Binary override */
  589.         Thisbinary = TRUE;
  590.     else if (zmanag == ZMAPND)
  591.         openmode = "a";
  592.  
  593.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  594.  
  595.     if (!name || !*name)
  596.         return OK;
  597.  
  598.     p = name + 1 + strlen(name);
  599.     if (*p) {    /* file coming from Unix or DOS system */
  600.         sscanf(p, "%ld%lo%o%lo%d%ld%d%d",
  601.           &Bytesleft, &Modtime, &Filemode,
  602.           &dummy, &Filesleft, &Totalleft, &dummy, &dummy);
  603.         if (Filemode & UNIXFILE)
  604.             ++Thisbinary;
  605.         if (Verbose) {
  606.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  607.               name, Bytesleft, Modtime, Filemode);
  608.             fprintf(stderr,  "YMODEM header: %s\n", p);
  609.         }
  610.     }
  611.  
  612.  
  613.     else {        /* File coming from CP/M system */
  614.         for (p=name; *p; ++p)        /* change / to _ */
  615.             if ( *p == '/')
  616.                 *p = '_';
  617.  
  618.         if ( *--p == '.')        /* zap trailing period */
  619.             *p = 0;
  620.     }
  621.  
  622.     strcpy(Pathname, name);
  623.     checkpath(name);
  624.  
  625.     if (*name && stat(name, &f)!= -1) {
  626.         zmanag &= ZMMASK;
  627.         vfile("Current %s is %ld %lo", name, f.st_size, f.st_mtime);
  628.         if (Thisbinary && zconv==ZCRESUM) {
  629.             rxbytes = f.st_size & ~511;
  630.             if (Bytesleft < rxbytes) {
  631.                 rxbytes = 0;  goto doopen;
  632.             } else
  633.                 openit(name, "r+");
  634.             if ( !fout)
  635.                 return ZFERR;
  636.             if (fseek(fout, rxbytes, 0)) {
  637.                 closeit();
  638.                 return ZFERR;
  639.             }
  640.             vfile("Crash recovery at %ld", rxbytes);
  641.             return 0;
  642.         }
  643.         else if ((zmanag==ZMNEW) ||
  644.           ((zmanag==ZMNEWL) && Bytesleft <= f.st_size) ) {
  645.             if ((f.st_mtime+1) >= Modtime)
  646.                 goto skipfile;
  647.             goto doopen;
  648.         }
  649.         switch (zmanag & ZMMASK) {
  650.         case ZMCLOB:
  651.         case ZMAPND:
  652.             goto doopen;
  653.         default:
  654.             goto skipfile;
  655.         }
  656.     } else if (zmanag & ZMSKNOLOC) {
  657. skipfile:
  658.         vfile("Skipping %s", name);
  659.         return ZSKIP;
  660.     }
  661. doopen:
  662.     openit(name, openmode);
  663. #ifdef MD
  664.     if ( !fout)
  665.         if (make_dirs(name))
  666.             openit(name, openmode);
  667. #endif
  668.     if ( !fout)
  669.         return ZFERR;
  670.     return 0;
  671. }
  672.  
  673. openit(name, openmode)
  674. char *name, *openmode;
  675. {
  676.     fout = fopen(name, openmode);
  677. }
  678.  
  679. #ifdef MD
  680. /*
  681.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  682.  */
  683.  
  684. /*
  685.  * After a file/link/symlink/dir creation has failed, see if
  686.  * it's because some required directory was not present, and if
  687.  * so, create all required dirs.
  688.  */
  689. make_dirs(pathname)
  690. register char *pathname;
  691. {
  692.     register char *p;        /* Points into path */
  693.     int madeone = 0;        /* Did we do anything yet? */
  694.     int save_errno = errno;        /* Remember caller's errno */
  695.     char *strchr();
  696.  
  697.     if (errno != ENOENT)
  698.         return 0;        /* Not our problem */
  699.  
  700.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  701.         /* Avoid mkdir of empty string, if leading or double '/' */
  702.         if (p == pathname || p[-1] == '/')
  703.             continue;
  704.         /* Avoid mkdir where last part of path is '.' */
  705.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  706.             continue;
  707.         *p = 0;                /* Truncate the path there */
  708.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  709.             vfile("Made directory %s\n", pathname);
  710.             madeone++;        /* Remember if we made one */
  711.             *p = '/';
  712.             continue;
  713.         }
  714.         *p = '/';
  715.         if (errno == EEXIST)        /* Directory already exists */
  716.             continue;
  717.         /*
  718.          * Some other error in the mkdir.  We return to the caller.
  719.          */
  720.         break;
  721.     }
  722.     errno = save_errno;        /* Restore caller's errno */
  723.     return madeone;            /* Tell them to retry if we made one */
  724. }
  725.  
  726. #if (MD != 2)
  727. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  728. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  729. #define TERM_VALUE(status)    ((status) >> 8)
  730. /*
  731.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  732.  */
  733. mkdir(dpath, dmode)
  734. char *dpath;
  735. int dmode;
  736. {
  737.     int cpid, status;
  738.     struct stat statbuf;
  739.  
  740.     if (stat(dpath,&statbuf) == 0) {
  741.         errno = EEXIST;        /* Stat worked, so it already exists */
  742.         return -1;
  743.     }
  744.  
  745.     /* If stat fails for a reason other than non-existence, return error */
  746.     if (errno != ENOENT) return -1; 
  747.  
  748.     switch (cpid = fork()) {
  749.  
  750.     case -1:            /* Error in fork() */
  751.         return(-1);        /* Errno is set already */
  752.  
  753.     case 0:                /* Child process */
  754.         /*
  755.          * Cheap hack to set mode of new directory.  Since this
  756.          * child process is going away anyway, we zap its umask.
  757.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  758.          * directory.  Does anybody care?
  759.          */
  760.         status = umask(0);    /* Get current umask */
  761.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  762.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  763.         _exit(2);        /* Can't exec /bin/mkdir */
  764.     
  765.     default:            /* Parent process */
  766.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  767.     }
  768.  
  769.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  770.         errno = EIO;        /* We don't know why, but */
  771.         return -1;        /* /bin/mkdir failed */
  772.     }
  773.  
  774.     return 0;
  775. }
  776. #endif /* MD != 2 */
  777. #endif /* MD */
  778.  
  779. /*
  780.  * Putsec writes the n characters of buf to receive file fout.
  781.  *  If not in binary mode, carriage returns, and all characters
  782.  *  starting with CPMEOF are discarded.
  783.  */
  784. putsec(buf, n)
  785. char *buf;
  786. register n;
  787. {
  788.     register char *p;
  789.  
  790.     if (n == 0)
  791.         return OK;
  792.     if (Thisbinary) {
  793.         for (p=buf; --n>=0; )
  794.             putc( *p++, fout);
  795.     }
  796.     else {
  797.         if (Eofseen)
  798.             return OK;
  799.         for (p=buf; --n>=0; ++p ) {
  800.             if ( *p == '\r')
  801.                 continue;
  802.             if (*p == CPMEOF) {
  803.                 Eofseen=TRUE; return OK;
  804.             }
  805.             putc(*p ,fout);
  806.         }
  807.     }
  808.     return OK;
  809. }
  810.  
  811. /*
  812.  * substr(string, token) searches for token in string s
  813.  * returns pointer to token within string if found, NULL otherwise
  814.  */
  815. char *
  816. substr(s, t)
  817. register char *s,*t;
  818. {
  819.     register char *ss,*tt;
  820.     /* search for first char of token */
  821.     for (ss=s; *s; s++)
  822.         if (*s == *t)
  823.             /* compare token with substring */
  824.             for (ss=s,tt=t; ;) {
  825.                 if (*tt == 0)
  826.                     return s;
  827.                 if (*ss++ != *tt++)
  828.                     break;
  829.             }
  830.     return NULL;
  831. }
  832.  
  833.  
  834. /*
  835.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  836.  * If called as rb use YMODEM protocol
  837.  */
  838. chkinvok(s)
  839. char *s;
  840. {
  841.     register char *p;
  842.  
  843.     p = s;
  844.     while (*p == '-')
  845.         s = ++p;
  846.     while (*p)
  847.         if (*p++ == '/')
  848.             s = p;
  849.     if (*s == 'v') {
  850.         Verbose=1; ++s;
  851.     }
  852.     Progname = s;
  853.     if (s[0]=='r' && s[1]=='z')
  854.         Batch = TRUE;
  855.     if (s[0]=='r' && s[1]=='c')
  856.         Crcflg = TRUE;
  857.     if (s[0]=='r' && s[1]=='b')
  858.         Batch = Nozmodem = TRUE;
  859. }
  860.  
  861. /*
  862.  * Totalitarian Communist pathname processing
  863.  */
  864. checkpath(name)
  865. char *name;
  866. {
  867.     if (Restricted) {
  868.         if (fopen(name, "r") != NULL) {
  869.             canit();
  870.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  871.             bibi(-1);
  872.         }
  873.         /* restrict pathnames to current tree or uucppublic */
  874.         if ( substr(name, "../")
  875.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  876.             canit();
  877.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  878.             bibi(-1);
  879.         }
  880.     }
  881. }
  882. /*
  883.  * Ack a ZFIN packet, let byegones be byegones
  884.  */
  885. void
  886. ackbibi()
  887. {
  888.     register n;
  889.  
  890.     vfile("ackbibi:");
  891.     Readnum = 1;
  892.     stohdr(0L);
  893.     for (n=3; --n>=0; ) {
  894.         purgeline();
  895.         zshhdr(4,ZFIN, Txhdr);
  896.         switch (readline(100)) {
  897.         case 'O':
  898.             readline(1);    /* Discard 2nd 'O' */
  899.             vfile("ackbibi complete");
  900.             return;
  901.         case RCDO:
  902.             return;
  903.         case TIMEOUT:
  904.         default:
  905.             break;
  906.         }
  907.     }
  908. }
  909.  
  910.  
  911. /*
  912.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  913.  *  Handles ZSINIT frame
  914.  *  Return ZFILE if Zmodem filename received, -1 on error,
  915.  *   ZCOMPL if transaction finished,  else 0
  916.  */
  917. tryz()
  918. {
  919.     register c, n;
  920.     register cmdzack1flg;
  921.  
  922.     if (Nozmodem)        /* Check for "rb" program name */
  923.         return 0;
  924.  
  925.  
  926.     for (n=15; --n>=0; ) {
  927.         /* Set buffer length (0) and capability flags */
  928. #ifdef SEGMENTS
  929.         stohdr(SEGMENTS*1024L);
  930. #else
  931.         stohdr(0L);
  932. #endif
  933. #ifdef CANBREAK
  934.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  935. #else
  936.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  937. #endif
  938.         if (Zctlesc)
  939.             Txhdr[ZF0] |= TESCCTL;
  940.         Txhdr[ZF0] |= CANRLE;
  941.         Txhdr[ZF1] = CANVHDR;
  942.         /* tryzhdrtype may == ZRINIT */
  943.         zshhdr(4,tryzhdrtype, Txhdr);
  944.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  945.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  946. again:
  947.         switch (zgethdr(Rxhdr, 0)) {
  948.         case ZRQINIT:
  949.             if (Rxhdr[ZF3] & 0x80)
  950.                 Usevhdrs = 1;    /* we can var header */
  951.             continue;
  952.         case ZEOF:
  953.             continue;
  954.         case TIMEOUT:
  955.             continue;
  956.         case ZFILE:
  957.             zconv = Rxhdr[ZF0];
  958.             zmanag = Rxhdr[ZF1];
  959.             ztrans = Rxhdr[ZF2];
  960.             if (Rxhdr[ZF3] & ZCANVHDR)
  961.                 Usevhdrs = TRUE;
  962.             tryzhdrtype = ZRINIT;
  963.             c = zrdata(secbuf, 1024);
  964.             if (c == GOTCRCW)
  965.                 return ZFILE;
  966.             zshhdr(4,ZNAK, Txhdr);
  967.             goto again;
  968.         case ZSINIT:
  969.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  970.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  971.                 stohdr(1L);
  972.                 zshhdr(4,ZACK, Txhdr);
  973.                 goto again;
  974.             }
  975.             zshhdr(4,ZNAK, Txhdr);
  976.             goto again;
  977.         case ZFREECNT:
  978.             stohdr(getfree());
  979.             zshhdr(4,ZACK, Txhdr);
  980.             goto again;
  981.         case ZCOMMAND:
  982.             cmdzack1flg = Rxhdr[ZF0];
  983.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  984.                 if (cmdzack1flg & ZCACK1)
  985.                     stohdr(0L);
  986.                 else
  987.                     stohdr((long)sys2(secbuf));
  988.                 purgeline();    /* dump impatient questions */
  989.                 do {
  990.                     zshhdr(4,ZCOMPL, Txhdr);
  991.                 }
  992.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  993.                 ackbibi();
  994.                 if (cmdzack1flg & ZCACK1)
  995.                     exec2(secbuf);
  996.                 return ZCOMPL;
  997.             }
  998.             zshhdr(4,ZNAK, Txhdr); goto again;
  999.         case ZCOMPL:
  1000.             goto again;
  1001.         default:
  1002.             continue;
  1003.         case ZFIN:
  1004.             ackbibi(); return ZCOMPL;
  1005.         case ZCAN:
  1006.             return ERROR;
  1007.         }
  1008.     }
  1009.     return 0;
  1010. }
  1011.  
  1012. /*
  1013.  * Receive 1 or more files with ZMODEM protocol
  1014.  */
  1015. rzfiles()
  1016. {
  1017.     register c;
  1018.  
  1019.     for (;;) {
  1020.         switch (c = rzfile()) {
  1021.         case ZEOF:
  1022.         case ZSKIP:
  1023.             switch (tryz()) {
  1024.             case ZCOMPL:
  1025.                 return OK;
  1026.             default:
  1027.                 return ERROR;
  1028.             case ZFILE:
  1029.                 break;
  1030.             }
  1031.             continue;
  1032.         default:
  1033.             return c;
  1034.         case ERROR:
  1035.             return ERROR;
  1036.         }
  1037.     }
  1038. }
  1039.  
  1040. /*
  1041.  * Receive a file with ZMODEM protocol
  1042.  *  Assumes file name frame is in secbuf
  1043.  */
  1044. rzfile()
  1045. {
  1046.     register c, n;
  1047.  
  1048.     Eofseen=FALSE;
  1049.     n = 20; rxbytes = 0l;
  1050.  
  1051.     if (c = procheader(secbuf)) {
  1052.         return (tryzhdrtype = c);
  1053.     }
  1054.  
  1055.     for (;;) {
  1056. #ifdef SEGMENTS
  1057.         chinseg = 0;
  1058. #endif
  1059.         stohdr(rxbytes);
  1060.         zshhdr(4,ZRPOS, Txhdr);
  1061. nxthdr:
  1062.         switch (c = zgethdr(Rxhdr, 0)) {
  1063.         default:
  1064.             vfile("rzfile: Wrong header %d", c);
  1065.             if ( --n < 0) {
  1066.                 sprintf(endmsg, "rzfile: Wrong header %d", c);
  1067.                 return ERROR;
  1068.             }
  1069.             continue;
  1070.         case ZCAN:
  1071.             sprintf(endmsg, "Sender CANcelled");
  1072.             return ERROR;
  1073.         case ZNAK:
  1074. #ifdef SEGMENTS
  1075.             putsec(secbuf, chinseg);
  1076.             chinseg = 0;
  1077. #endif
  1078.             if ( --n < 0) {
  1079.                 sprintf(endmsg, "rzfile: got ZNAK", c);
  1080.                 return ERROR;
  1081.             }
  1082.             continue;
  1083.         case TIMEOUT:
  1084. #ifdef SEGMENTS
  1085.             putsec(secbuf, chinseg);
  1086.             chinseg = 0;
  1087. #endif
  1088.             if ( --n < 0) {
  1089.                 sprintf(endmsg, "rzfile: TIMEOUT", c);
  1090.                 return ERROR;
  1091.             }
  1092.             continue;
  1093.         case ZFILE:
  1094.             zrdata(secbuf, 1024);
  1095.             continue;
  1096.         case ZEOF:
  1097. #ifdef SEGMENTS
  1098.             putsec(secbuf, chinseg);
  1099.             chinseg = 0;
  1100. #endif
  1101.             if (rclhdr(Rxhdr) != rxbytes) {
  1102.                 /*
  1103.                  * Ignore eof if it's at wrong place - force
  1104.                  *  a timeout because the eof might have gone
  1105.                  *  out before we sent our zrpos.
  1106.                  */
  1107.                 errors = 0;  goto nxthdr;
  1108.             }
  1109.             if (closeit()) {
  1110.                 tryzhdrtype = ZFERR;
  1111.                 vfile("rzfile: closeit returned <> 0");
  1112.                 sprintf(endmsg,"Error closing file");
  1113.                 return ERROR;
  1114.             }
  1115.             vfile("rzfile: normal EOF");
  1116.             return c;
  1117.         case ERROR:    /* Too much garbage in header search error */
  1118. #ifdef SEGMENTS
  1119.             putsec(secbuf, chinseg);
  1120.             chinseg = 0;
  1121. #endif
  1122.             if ( --n < 0) {
  1123.                 sprintf(endmsg, "Persistent CRC or other ERROR");
  1124.                 return ERROR;
  1125.             }
  1126.             zmputs(Attn);
  1127.             continue;
  1128.         case ZSKIP:
  1129. #ifdef SEGMENTS
  1130.             putsec(secbuf, chinseg);
  1131.             chinseg = 0;
  1132. #endif
  1133.             Modtime = 1;
  1134.             closeit();
  1135.             sprintf(endmsg, "Sender SKIPPED file");
  1136.             return c;
  1137.         case ZDATA:
  1138.             if (rclhdr(Rxhdr) != rxbytes) {
  1139.                 if ( --n < 0) {
  1140.                     sprintf(endmsg,"Data has bad addr");
  1141.                     return ERROR;
  1142.                 }
  1143. #ifdef SEGMENTS
  1144.                 putsec(secbuf, chinseg);
  1145.                 chinseg = 0;
  1146. #endif
  1147.                 zmputs(Attn);  continue;
  1148.             }
  1149. moredata:
  1150.             if (Verbose>1)
  1151.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1152.                   rxbytes, Crc32r?" CRC-32":"");
  1153. #ifdef SEGMENTS
  1154.             if (chinseg >= (1024 * SEGMENTS)) {
  1155.                 putsec(secbuf, chinseg);
  1156.                 chinseg = 0;
  1157.             }
  1158.             switch (c = zrdata(secbuf+chinseg, 1024))
  1159. #else
  1160.             switch (c = zrdata(secbuf, 1024))
  1161. #endif
  1162.             {
  1163.             case ZCAN:
  1164. #ifdef SEGMENTS
  1165.                 putsec(secbuf, chinseg);
  1166.                 chinseg = 0;
  1167. #endif
  1168.                 sprintf(endmsg, "Sender CANcelled");
  1169.                 return ERROR;
  1170.             case ERROR:    /* CRC error */
  1171. #ifdef SEGMENTS
  1172.                 putsec(secbuf, chinseg);
  1173.                 chinseg = 0;
  1174. #endif
  1175.                 if ( --n < 0) {
  1176.                     sprintf(endmsg, "Persistent CRC or other ERROR");
  1177.                     return ERROR;
  1178.                 }
  1179.                 zmputs(Attn);
  1180.                 continue;
  1181.             case TIMEOUT:
  1182. #ifdef SEGMENTS
  1183.                 putsec(secbuf, chinseg);
  1184.                 chinseg = 0;
  1185. #endif
  1186.                 if ( --n < 0) {
  1187.                     sprintf(endmsg, "TIMEOUT");
  1188.                     return ERROR;
  1189.                 }
  1190.                 continue;
  1191.             case GOTCRCW:
  1192.                 n = 20;
  1193. #ifdef SEGMENTS
  1194.                 chinseg += Rxcount;
  1195.                 putsec(secbuf, chinseg);
  1196.                 chinseg = 0;
  1197. #else
  1198.                 putsec(secbuf, Rxcount);
  1199. #endif
  1200.                 rxbytes += Rxcount;
  1201.                 stohdr(rxbytes);
  1202.                 sendline(XON);
  1203.                 zshhdr(4,ZACK, Txhdr);
  1204.                 goto nxthdr;
  1205.             case GOTCRCQ:
  1206.                 n = 20;
  1207. #ifdef SEGMENTS
  1208.                 chinseg += Rxcount;
  1209. #else
  1210.                 putsec(secbuf, Rxcount);
  1211. #endif
  1212.                 rxbytes += Rxcount;
  1213.                 stohdr(rxbytes);
  1214.                 zshhdr(4,ZACK, Txhdr);
  1215.                 goto moredata;
  1216.             case GOTCRCG:
  1217.                 n = 20;
  1218. #ifdef SEGMENTS
  1219.                 chinseg += Rxcount;
  1220. #else
  1221.                 putsec(secbuf, Rxcount);
  1222. #endif
  1223.                 rxbytes += Rxcount;
  1224.                 goto moredata;
  1225.             case GOTCRCE:
  1226.                 n = 20;
  1227. #ifdef SEGMENTS
  1228.                 chinseg += Rxcount;
  1229. #else
  1230.                 putsec(secbuf, Rxcount);
  1231. #endif
  1232.                 rxbytes += Rxcount;
  1233.                 goto nxthdr;
  1234.             }
  1235.         }
  1236.     }
  1237. }
  1238.  
  1239.  
  1240. /*
  1241.  * Close the receive dataset, return OK or ERROR
  1242.  */
  1243. closeit()
  1244. {
  1245.     time_t time();
  1246.  
  1247.     if (fclose(fout)==ERROR) {
  1248.         fprintf(stderr, "file close ERROR\n");
  1249.         return ERROR;
  1250.     }
  1251.     if (Modtime) {
  1252.         timep[0] = time(NULL);
  1253.         timep[1] = Modtime;
  1254.         utime(Pathname, timep);
  1255.     }
  1256.     if (
  1257. #ifdef POSIX
  1258.     S_ISREG(Filemode)
  1259. #else
  1260.     (Filemode&S_IFMT) == S_IFREG
  1261. #endif
  1262.     )
  1263.         chmod(Pathname, (unsigned short)(07777 & Filemode));
  1264.     return OK;
  1265. }
  1266.  
  1267.  
  1268. /*
  1269.  * Strip leading ! if present, do shell escape. 
  1270.  */
  1271. sys2(s)
  1272. register char *s;
  1273. {
  1274.     if (*s == '!')
  1275.         ++s;
  1276.     return system(s);
  1277. }
  1278. /*
  1279.  * Strip leading ! if present, do exec.
  1280.  */
  1281. exec2(s)
  1282. register char *s;
  1283. {
  1284.     if (*s == '!')
  1285.         ++s;
  1286.     mode(0);
  1287.     execl("/bin/sh", "sh", "-c", s);
  1288. }
  1289.  
  1290. /* End of rz.c */
  1291.